package rpc

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"reflect"
	"strings"
	"sync"
)

// Request 通用请求结构
type Request struct {
	ServiceMethod string          `json:"method"`
	Data          json.RawMessage `json:"data"`
}

// Response 通用响应结构
type Response struct {
	ServiceMethod string          `json:"method"`
	Success       bool            `json:"success"`
	Data          json.RawMessage `json:"data,omitempty"`
	Error         string          `json:"error,omitempty"`
}

type Service interface {
	Name() string
}

/* Server 包含多个 Service */
type Server struct {
	services map[string]Service
	mu       sync.Mutex
}

func NewServer() *Server {
	return &Server{
		services: make(map[string]Service),
	}
}

/* 注册服务 */
func (s *Server) RegisterService(service Service) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	name := service.Name()
	if _, exists := s.services[name]; exists {
		return fmt.Errorf("service already registered: %s", name)
	}

	s.services[name] = service
	return nil
}

/* 处理单个连接 */
func (s *Server) ServeConn(conn io.ReadWriteCloser) {
	defer conn.Close()

	decoder := json.NewDecoder(conn)
	encoder := json.NewEncoder(conn)

	for {
		var req Request
		if err := decoder.Decode(&req); err != nil {
			if err != io.EOF {
				_ = encoder.Encode(Response{
					ServiceMethod: req.ServiceMethod,
					Success:       false,
					Error:         err.Error(),
				})
			}
			return
		}

		resp := s.handleRequest(&req)
		_ = encoder.Encode(resp)
	}
}

func (s *Server) handleRequest(req *Request) *Response {
	var resp Response
	resp.ServiceMethod = req.ServiceMethod

	parts := strings.Split(req.ServiceMethod, ".")
	if len(parts) != 2 {
		resp.Error = "method format should be Service.Method"
		return &resp
	}
	serviceName, methodName := parts[0], parts[1]

	s.mu.Lock()
	service, ok := s.services[serviceName]
	s.mu.Unlock()

	if !ok {
		resp.Error = fmt.Sprintf("service not found: %s", serviceName)
		return &resp
	}

	sv := reflect.ValueOf(service)
	method := sv.MethodByName(methodName)
	if !method.IsValid() {
		resp.Error = fmt.Sprintf("method not found: %s", methodName)
		return &resp
	}

	argType := method.Type().In(0)
	args := reflect.New(argType).Interface()

	if err := json.Unmarshal(req.Data, args); err != nil {
		resp.Error = fmt.Sprintf("decode args error: %v", err)
		return &resp
	}

	out := method.Call([]reflect.Value{reflect.ValueOf(args).Elem()})

	if len(out) != 2 {
		resp.Error = "method should return (result, error)"
		return &resp
	}

	if !out[1].IsNil() {
		resp.Error = out[1].Interface().(error).Error()
		return &resp
	}

	resultData, err := json.Marshal(out[0].Interface())
	if err != nil {
		resp.Error = fmt.Sprintf("encode result error: %v", err)
		return &resp
	}

	resp.Success = true
	resp.Data = resultData
	return &resp
}

type Client struct {
	conn    io.ReadWriteCloser
	encoder *json.Encoder
	decoder *json.Decoder
	mu      sync.Mutex
}

func NewClient(conn io.ReadWriteCloser) *Client {
	return &Client{
		conn:    conn,
		encoder: json.NewEncoder(conn),
		decoder: json.NewDecoder(conn),
	}
}

func (c *Client) Call(serviceMethod string, args, reply interface{}) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	argData, err := json.Marshal(args)
	if err != nil {
		return err
	}

	req := Request{
		ServiceMethod: serviceMethod,
		Data:          argData,
	}

	if err := c.encoder.Encode(&req); err != nil {
		return err
	}

	var resp Response
	if err := c.decoder.Decode(&resp); err != nil {
		return err
	}

	if !resp.Success {
		return errors.New(resp.Error)
	}

	if reply != nil && len(resp.Data) > 0 {
		return json.Unmarshal(resp.Data, reply)
	}

	return nil
}

func (c *Client) Close() error {
	return c.conn.Close()
}
